package com.gradecak.alfresco.mvc.servlet;

import java.util.Comparator;

import org.springframework.util.PathMatcher;

/**
 * Comparator capable of sorting {@link RequestMappingInfo}s (RHIs) so that sorting a list with this comparator will
 * result in: <ul> <li>RHIs with {@linkplain RequestMappingInfo#matchedPaths better matched paths} take prescedence
 * over those with a weaker match (as expressed by the {@linkplain PathMatcher#getPatternComparator(String) path
 * pattern comparator}.) Typically, this means that patterns without wild cards and uri templates will be ordered
 * before those without.</li> <li>RHIs with one single {@linkplain RequestMappingInfo#methods request method} will be
 * ordered before those without a method, or with more than one method.</li> <li>RHIs with more {@linkplain
 * RequestMappingInfo#params request parameters} will be ordered before those with less parameters</li> </ol>
 */
class RequestMappingInfoComparator implements Comparator<RequestMappingInfo> {

	private final Comparator<String> pathComparator;

	RequestMappingInfoComparator(Comparator<String> pathComparator) {
		this.pathComparator = pathComparator;
	}

	public int compare(RequestMappingInfo info1, RequestMappingInfo info2) {
		int pathComparison = pathComparator.compare(info1.bestMatchedPath(), info2.bestMatchedPath());
		if (pathComparison != 0) {
			return pathComparison;
		}
		int info1ParamCount = info1.params.length;
		int info2ParamCount = info2.params.length;
		if (info1ParamCount != info2ParamCount) {
			return info2ParamCount - info1ParamCount;
		}
		int info1HeaderCount = info1.headers.length;
		int info2HeaderCount = info2.headers.length;
		if (info1HeaderCount != info2HeaderCount) {
			return info2HeaderCount - info1HeaderCount;
		}
		int info1MethodCount = info1.methods.length;
		int info2MethodCount = info2.methods.length;
		if (info1MethodCount == 0 && info2MethodCount > 0) {
			return 1;
		}
		else if (info2MethodCount == 0 && info1MethodCount > 0) {
			return -1;
		}
		else if (info1MethodCount == 1 & info2MethodCount > 1) {
			return -1;
		}
		else if (info2MethodCount == 1 & info1MethodCount > 1) {
			return 1;
		}
		return 0;
	}
}
